/* 逻辑分析仪硬件抽象层示例代码

   此示例代码属于公共领域（或根据您的选择采用CC0许可）

   除非适用法律要求或以书面形式同意，本软件按"原样"分发，
   不附带任何明示或暗示的担保或条件。
*/
#include "logic_analyzer_hal.h"                // 逻辑分析仪HAL头文件
#include "logic_analyzer_ll.h"                 // 逻辑分析仪底层驱动头文件
#include "logic_analyzer_hi_level_interrupt.h" // 高级中断处理头文件
#include "soc/soc.h"                           // SoC相关定义
#include "soc/dport_access.h"                  // DPORT访问接口
#include "esp_log.h"                           // ESP日志功能
#include "string.h"                            // 字符串处理
#include "rom/cache.h"                         // 缓存相关ROM函数
#include "esp_cache.h"                         // ESP缓存管理（ESP内存管理）
#include "esp_psram.h"                         // PSRAM支持

#define LA_TASK_STACK 2048 // 逻辑分析仪任务栈大小
#define DMA_FRAME 4032     // DMA帧大小（字节）

// 帧缓冲区和DMA描述符结构
static la_frame_t la_frame = {
    .fb.buf = NULL, // 帧缓冲区指针初始化为NULL
    .fb.len = 0,    // 帧缓冲区长度初始化为0（单位：字节，每个样本=2字节）
    .dma = NULL     // DMA描述符指针初始化为NULL
};

static TaskHandle_t logic_analyzer_task_handle = 0; // 逻辑分析仪主任务句柄
static int logic_analyzer_started = 0;              // DMA启动标志

/**
 * @brief 获取逻辑分析仪硬件参数
 * @param hw 硬件参数结构体指针
 * @return 返回ESP_OK表示成功
 */
esp_err_t logic_analyzer_get_hw_param(logic_analyzer_hw_param_t *hw)
{
    // 检查PSRAM是否初始化
    if (esp_psram_is_initialized())
    {
        hw->available_psram = 1; // PSRAM可用
    }
    else
    {
        hw->available_psram = 0; // PSRAM不可用
        hw->current_psram = 0;
    }

    // 确保当前PSRAM设置不超过可用PSRAM
    if (hw->current_psram > hw->available_psram)
    {
        hw->current_psram = hw->available_psram;
    }
    if (hw->current_psram < 0)
    {
        hw->current_psram = 0;
    }

    // 设置通道数范围
    hw->max_channels = LA_HW_MAX_CHANNELS; // 最大通道数
    hw->min_channels = LA_HW_MIN_CHANNELS; // 最小通道数
    if (hw->current_channels > LA_HW_MAX_CHANNELS)
    {
        hw->current_channels = LA_HW_MAX_CHANNELS;
    }
    if (hw->current_channels < LA_HW_MIN_CHANNELS)
    {
        hw->current_channels = LA_HW_MIN_CHANNELS;
    }

    int max_ram = 0;
    if (hw->current_psram) // 使用PSRAM
    {
        max_ram = (int)heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM); // 获取PSRAM最大空闲块
        if (hw->current_channels > 4)
        {
            // 根据通道数设置采样率和样本数
            hw->max_sample_rate = (hw->current_channels == 8 ? LA_HW_MAX_PSRAM_8_SAMPLE_RATE : LA_HW_MAX_PSRAM_16_SAMPLE_RATE);
            hw->min_sample_rate = (hw->current_channels == 8 ? LA_HW_MIN_8_SAMPLE_RATE : LA_HW_MIN_16_SAMPLE_RATE);
            hw->max_sample_cnt = (hw->current_channels == 8 ? max_ram : max_ram / 2);
            hw->min_sample_cnt = (hw->current_channels == 8 ? LA_HW_MIN_8_SAMPLE_CNT : LA_HW_MIN_16_SAMPLE_CNT);
        }
        else // 通道数为4
        {
            hw->max_sample_rate = LA_HW_MAX_PSRAM_8_SAMPLE_RATE; // 4通道最大采样率
            hw->min_sample_rate = LA_HW_MIN_8_SAMPLE_RATE;       // 4通道最小采样率
            hw->max_sample_cnt = LA_HW_MAX_PSRAM_8_SAMPLE_CNT;   // 4通道最大样本数
            hw->min_sample_cnt = LA_HW_MIN_8_SAMPLE_CNT;         // 4通道最小样本数
        }
    }
    else // 使用RAM
    {
        max_ram = (int)heap_caps_get_largest_free_block(MALLOC_CAP_DMA); // 获取DMA内存最大空闲块
        if (hw->current_channels > 4)
        {
            hw->max_sample_rate = (hw->current_channels == 8 ? LA_HW_MAX_RAM_8_SAMPLE_RATE : LA_HW_MAX_RAM_16_SAMPLE_RATE);
            hw->min_sample_rate = (hw->current_channels == 8 ? LA_HW_MIN_8_SAMPLE_RATE : LA_HW_MIN_16_SAMPLE_RATE);
            hw->max_sample_cnt = (hw->current_channels == 8 ? max_ram : max_ram / 2);
            hw->min_sample_cnt = (hw->current_channels == 8 ? LA_HW_MIN_8_SAMPLE_CNT : LA_HW_MIN_16_SAMPLE_CNT);
        }
        else
        {
            hw->max_sample_rate = LA_HW_MAX_RAM_8_SAMPLE_RATE; // 4通道最大采样率
            hw->min_sample_rate = LA_HW_MIN_8_SAMPLE_RATE;     // 4通道最小采样率
            hw->max_sample_cnt = LA_HW_MAX_RAM_8_SAMPLE_CNT;   // 4通道最大样本数
            hw->min_sample_cnt = LA_HW_MIN_8_SAMPLE_CNT;       // 4通道最小样本数
        }
    }
    return ESP_OK;
}

#ifdef CONFIG_IDF_TARGET_ESP32
/**
 * @brief ESP32专用：交换缓冲区中的样本顺序
 * @param buf 缓冲区指针
 * @param cnt 样本计数
 */
static inline void swap_buf(uint16_t *buf, int cnt)
{
    uint16_t tmp;
    for (int i = 0; i < cnt; i += 2)
    {
        tmp = buf[i];
        buf[i] = buf[i + 1];
        buf[i + 1] = tmp;
    }
}
#endif

/**
 * @brief 分配DMA描述符
 * @param size 样本帧缓冲区大小（字节）
 * @param buffer 样本帧缓冲区指针
 * @return 返回DMA描述符指针（NULL表示内存不足）
 */
static lldesc_t *allocate_dma_descriptors(uint32_t size, uint8_t *buffer)
{
    uint32_t count = size / DMA_FRAME;     // 计算完整DMA帧数量
    uint32_t last_size = size % DMA_FRAME; // 计算最后一帧的字节数

    // 分配DMA描述符内存（DMA能力内存）
    lldesc_t *dma = (lldesc_t *)heap_caps_malloc((count + 1) * sizeof(lldesc_t), MALLOC_CAP_DMA);
    if (dma == NULL)
    {
        return dma;
    }

    // 初始化每个DMA描述符
    int x = 0;
    for (; x < count; x++)
    {
        dma[x].size = DMA_FRAME;                // 帧大小
        dma[x].length = DMA_FRAME;              // 数据长度
        dma[x].sosf = 0;                        // 帧开始标志
        dma[x].eof = 0;                         // 帧结束标志
        dma[x].owner = 1;                       // DMA拥有者标志
        dma[x].buf = buffer + DMA_FRAME * x;    // 缓冲区指针
        dma[x].empty = (uint32_t)&dma[(x + 1)]; // 下一个描述符地址
    }

    // 初始化最后一个描述符
    dma[x].size = last_size;
    dma[x].length = last_size;
    dma[x].sosf = 0;
    dma[x].eof = 1; // 设置为帧结束
    dma[x].owner = 1;
    dma[x].buf = buffer + DMA_FRAME * x;
    dma[x].empty = 0; // 无下一个描述符

    return dma;
}

/**
 * @brief 完全停止逻辑分析仪并释放所有资源
 */
static void logic_analyzer_stop(void)
{
    logic_analyzer_ll_stop();               // 停止DMA传输
    logic_analyzer_ll_deinit_dma_eof_isr(); // 反初始化DMA EOF中断

    // 释放DMA描述符内存
    if (la_frame.dma)
    {
        free(la_frame.dma);
        la_frame.dma = NULL;
    }

    // 释放帧缓冲区内存
    if (la_frame.fb.buf)
    {
        free(la_frame.fb.buf);
        la_frame.fb.buf = NULL;
        la_frame.fb.len = 0;
    }

    logic_analyzer_started = 0; // 重置启动标志
}

/**
 * @brief 逻辑分析仪主任务
 * @param arg 指向配置结构体的指针（包含回调函数）
 */
static void logic_analyzer_task(void *arg)
{
    int noTimeout;
    logic_analyzer_config_t *cfg = (logic_analyzer_config_t *)arg;

    while (1)
    {
        // 等待任务通知（带超时）
        noTimeout = ulTaskNotifyTake(pdFALSE, cfg->meashure_timeout);
        if (noTimeout) // DMA数据就绪
        {
#ifdef CONFIG_IDF_TARGET_ESP32
            // ESP32需要交换样本顺序
            swap_buf((uint16_t *)la_frame.fb.buf, la_frame.fb.len / (cfg->number_channels / 8));
#endif

#ifdef LA_HW_PSRAM
            // 同步PSRAM和CPU缓存（仅当使用PSRAM时）
            if (cfg->samples_to_psram)
            {
                int err = esp_cache_msync(la_frame.fb.buf, la_frame.fb.len, ESP_CACHE_MSYNC_FLAG_UNALIGNED);
                if (err)
                    ESP_LOGE("CACHE", "ERR %x", err);
            }
#endif

            // 计算实际样本数
            int l_samples = (cfg->number_channels > 4) ? (la_frame.fb.len / (cfg->number_channels / 8)) : la_frame.fb.len * 2;
            ESP_LOGI("MdLink", "samples:%d, rate:%d, channels:%d", l_samples, logic_analyzer_ll_get_sample_rate(cfg->sample_rate), cfg->number_channels);
            // 调用回调函数处理数据
            cfg->logic_analyzer_cb((uint8_t *)la_frame.fb.buf, l_samples,
                                   logic_analyzer_ll_get_sample_rate(cfg->sample_rate),
                                   cfg->number_channels);

            logic_analyzer_stop();                   // 停止逻辑分析仪
            vTaskDelete(logic_analyzer_task_handle); // 删除任务
            logic_analyzer_task_handle = NULL;
        } else // 超时
        {
#ifdef CONFIG_ANALYZER_USE_HI_LEVEL_INTERRUPT
            ll_hi_level_triggered_isr_timeout_stop(); // 恢复GPIO中断寄存器
#endif
           // ESP_LOGE("MdLink", "bug 3");

            cfg->logic_analyzer_cb(NULL, 0, 0, 0); // 调用超时回调
            logic_analyzer_stop();
            vTaskDelete(logic_analyzer_task_handle);
            logic_analyzer_task_handle = NULL;
        }
    }
}

/**
 * @brief 启动逻辑分析仪
 * @param config 配置参数（参见logic_analyzer_config_t结构）
 * @return 执行状态（ESP_OK表示成功）
 */
esp_err_t start_logic_analyzer(logic_analyzer_config_t *config)
{
    esp_err_t ret = 0;
    logic_analyzer_hw_param_t hw_param;

    // 获取当前硬件参数
    hw_param.current_channels = config->number_channels;
    hw_param.current_psram = config->samples_to_psram;
    logic_analyzer_get_hw_param(&hw_param);


    // 处理重启情况（测量超时为0）
    if (config->meashure_timeout == 0)
    {
        if (logic_analyzer_started)
        {
#ifdef CONFIG_ANALYZER_USE_HI_LEVEL_INTERRUPT
            ll_hi_level_triggered_isr_timeout_stop(); // 恢复GPIO中断
#endif
            ESP_LOGE("MdLink","bug 1" );
            config->logic_analyzer_cb(NULL, 0, 0, 0); // 调用回调
            logic_analyzer_stop();
            vTaskDelete(logic_analyzer_task_handle);
            logic_analyzer_task_handle = NULL;
        }
        else
        {
            ESP_LOGE("MdLink", "bug 2");

            config->logic_analyzer_cb(NULL, 0, 0, 0);
        }
        ret = ESP_OK;
        goto _retcode;
    }

    // 检查逻辑分析仪是否已启动
    if (logic_analyzer_started)
    {
        return ESP_ERR_INVALID_STATE;
    }
    logic_analyzer_started = 1;// 启动标志置位

    // 参数校验
    if (config->logic_analyzer_cb == NULL)
        goto _ret;
    if (config->number_channels > hw_param.max_channels || config->number_channels < hw_param.min_channels)
        goto _ret;

    // 检查GPIO引脚号是否合法
    for (int i = 0; i < config->number_channels; i++)
    {
        if (config->pin[i] > LA_HW_MAX_GPIO || config->pin[i] < LA_HW_MIN_GPIO)
            goto _ret;
    }
    if (config->pin_trigger > LA_HW_MAX_GPIO || config->pin_trigger < LA_HW_MIN_GPIO)
        goto _ret;

    // 检查触发边沿
    else if ((config->trigger_edge >= 0 && config->trigger_edge < GPIO_INTR_MAX) == 0)
        goto _ret;

    // 检查采样率
    if (config->sample_rate > hw_param.max_sample_rate || config->sample_rate < hw_param.min_sample_rate)
        goto _ret;

    // 检查样本数
    if (config->number_of_samples > hw_param.max_sample_cnt || config->number_of_samples < hw_param.min_sample_cnt)
        goto _ret;

    // 检查PSRAM模式
    if (config->samples_to_psram > hw_param.available_psram || config->samples_to_psram < 0)
        goto _ret;

    // 计算需要分配的字节数
    uint32_t bytes_to_alloc = config->number_channels > 4 ? (config->number_of_samples * (config->number_channels / 8)) : (config->number_of_samples / 2);

    // 分配帧缓冲区内存
    if (config->samples_to_psram == 0) // 检查配置是否不使用PSRAM（即使用内部RAM）
    {
        // 获取DMA内存中最大的空闲块大小
        uint32_t largest_free_block = heap_caps_get_largest_free_block(MALLOC_CAP_DMA);

        // 检查可用内存是否足够（包括帧缓冲区和DMA描述符所需空间）
        if (largest_free_block < bytes_to_alloc + ((bytes_to_alloc / DMA_FRAME) + 1) * sizeof(lldesc_t))
        {
            // 如果内存不足，则调整要分配的字节数，保留空间给DMA描述符
            bytes_to_alloc = largest_free_block - ((bytes_to_alloc / DMA_FRAME) + 2) * sizeof(lldesc_t);
        }

        // 打印分配前DMA堆内存状态（调试信息）
        ESP_LOGD("DMA HEAP Before", "All_dma_heap=%d Largest_dma_heap_block=%d",
                 heap_caps_get_free_size(MALLOC_CAP_DMA),           // 当前DMA堆总空闲大小
                 heap_caps_get_largest_free_block(MALLOC_CAP_DMA)); // 最大空闲块大小

        // 确保分配长度是4字节对齐（32位架构优化）
        la_frame.fb.len = bytes_to_alloc & ~0x3;
        // 在DMA内存中分配清零的内存块(la_frame.fb.len × 1 字节)
        la_frame.fb.buf = heap_caps_calloc(la_frame.fb.len, 1, MALLOC_CAP_DMA);

        // 打印分配后DMA堆内存状态（调试信息）
        ESP_LOGD("DMA HEAP After", "All_dma_heap=%d Largest_dma_heap_block=%d",
                 heap_caps_get_free_size(MALLOC_CAP_DMA),
                 heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
    }
    else // 使用PSRAM的情况
    {
        // 获取PSRAM中最大的空闲块大小
        uint32_t largest_free_block = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);

        // 检查PSRAM空间是否足够
        if (largest_free_block < bytes_to_alloc)
        {
            // 如果不足，调整要分配的字节数
            bytes_to_alloc = largest_free_block;
        }

        // 打印分配前PSRAM内存状态（调试信息）
        ESP_LOGD("DMA PSRAM HEAP Before", "All_dma_heap=%d Largest_dma_heap_block=%d",
                 heap_caps_get_free_size(MALLOC_CAP_SPIRAM),           // 当前PSRAM堆总空闲大小
                 heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM)); // 最大空闲块大小

        // 确保分配长度是GDMA_PSRAM_BURST对齐（PSRAM突发传输要求）
        la_frame.fb.len = bytes_to_alloc & ~(GDMA_PSRAM_BURST - 1);
        // 在PSRAM中分配对齐且清零的内存块
        la_frame.fb.buf = heap_caps_aligned_calloc(GDMA_PSRAM_BURST, la_frame.fb.len, 1, MALLOC_CAP_SPIRAM);

        // 打印分配后PSRAM内存状态（调试信息）
        ESP_LOGD("DMA PSRAM HEAP After", "All_dma_heap=%d Largest_dma_heap_block=%d",
                 heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
                 heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
    }
    if (la_frame.fb.buf == NULL)
    {
        ret = ESP_ERR_NO_MEM;
        goto _retcode;
    }
    ESP_LOGD("DMA HEAP", "Allocated %d bytes", la_frame.fb.len);
    // 分配DMA描述符
    la_frame.dma = allocate_dma_descriptors(la_frame.fb.len, la_frame.fb.buf);
    if (la_frame.dma == NULL)
    {
        ret = ESP_ERR_NO_MEM;
        goto _freebuf_ret;
    }

    // 配置底层驱动
    logic_analyzer_ll_config(config->pin, config->sample_rate, config->number_channels, &la_frame);

    // 创建主任务
    if (pdPASS != xTaskCreate(logic_analyzer_task, "la_task", LA_TASK_STACK * 4, config,
                              uxTaskPriorityGet(NULL), &logic_analyzer_task_handle))
    {
        ret = ESP_ERR_NO_MEM;
        goto _freedma_ret;
    }

    // 初始化DMA EOF中断
    ret = logic_analyzer_ll_init_dma_eof_isr(logic_analyzer_task_handle);
    if (ret != ESP_OK)
    {
        goto _freetask_ret;
    }

    // 启动测量
    if (config->pin_trigger < 0)
    {
        logic_analyzer_ll_start(); // 立即启动
    }
    else
    {
        logic_analyzer_ll_triggered_start(config->pin_trigger, config->trigger_edge); // 触发启动
    }
    return ESP_OK;

// 错误处理标签
_freetask_ret:
    vTaskDelete(logic_analyzer_task_handle);
_freedma_ret:
    free(la_frame.dma);
_freebuf_ret:
    free(la_frame.fb.buf);
_retcode:
    logic_analyzer_started = 0;
    return ret;
_ret:
    logic_analyzer_started = 0;
    return ESP_ERR_INVALID_ARG;
}